package godraw

import (
	"bufio"
	"bytes"
	"errors"
	"image"
	"image/color"
	"image/jpeg"

	"github.com/llgcode/draw2d/draw2dimg"
)

// ToImage bgr -> image.Image
func ToImage(data []byte, w, h int) (image.Image, error) {
	width := w
	height := h
	step := w * 3
	channels := 3

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	c := color.RGBA{
		R: uint8(0),
		G: uint8(0),
		B: uint8(0),
		A: uint8(255),
	}

	for y := 0; y < height; y++ {
		for x := 0; x < step; x = x + channels {
			c.B = uint8(data[y*step+x])
			c.G = uint8(data[y*step+x+1])
			c.R = uint8(data[y*step+x+2])
			if channels == 4 {
				c.A = uint8(data[y*step+x+3])
			}
			img.SetRGBA(int(x/channels), y, c)
		}
	}

	return img, nil
}

// Image2BGR img->bgr
func Image2BGR(img image.Image) []byte {
	bounds := img.Bounds()
	x := bounds.Dx()
	y := bounds.Dy()
	data := make([]byte, 0, x*y*3)
	for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
		for i := bounds.Min.X; i < bounds.Max.X; i++ {
			r, g, b, _ := img.At(i, j).RGBA()
			data = append(data, byte(b>>8), byte(g>>8), byte(r>>8))
		}
	}
	return data
}

// DrawRectangle draw rect
func DrawRectangle(img image.Image, rc image.Rectangle, clr color.RGBA, lw float64) error {

	l, t, r, b := rc.Min.X, rc.Min.Y, rc.Max.X, rc.Max.Y

	pt := []image.Point{
		image.Pt(l, t),
		image.Pt(l, r),
		image.Pt(r, b),
		image.Pt(r, l),
	}

	return DrawPolygon(img, pt, clr, lw)
}

// DrawPolygon draw polygon
func DrawPolygon(img image.Image, pt []image.Point, clr color.RGBA, lw float64) error {
	rgba, ok := img.(*image.RGBA)
	if !ok {
		return errors.New("IMAGE CONVERT TO RGBA ERROR")
	}

	pt = append(pt, pt[0])

	gc := draw2dimg.NewGraphicContext(rgba)
	gc.SetStrokeColor(clr)
	gc.SetLineWidth(lw)

	gc.BeginPath()
	start := pt[0]
	pt = pt[1:]
	gc.MoveTo((float64)(start.X), (float64)(start.Y))
	for _, v := range pt {
		gc.LineTo((float64)(v.X), (float64)(v.Y))
	}
	// gc.QuadCurveTo(100, 10, 10, 10)
	gc.Close()
	gc.Stroke()
	return nil
}

// ToJpeg bgr -> jpeg file
func ToJpeg(bgr []byte, w, h int, quality *int) ([]byte, error) {
	img, err := ToImage(bgr, w, h)
	if err != nil {
		return nil, err
	}
	return ImageToJpeg(img, quality)
}

// ImageToJpeg save to jpeg data
func ImageToJpeg(img image.Image, quality *int) ([]byte, error) {
	var o *jpeg.Options

	if quality != nil {
		o = &jpeg.Options{Quality: *quality}
	}
	var b bytes.Buffer
	w := bufio.NewWriter(&b)
	err := jpeg.Encode(w, img, o)
	if err != nil {
		return nil, err
	}
	return b.Bytes(), err
}
